using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.ComponentModel;

namespace ResourceBlender_Express {
    /// <summary>
    /// Allows a user to select an application, languages and bundles.
    /// </summary>
    public partial class ApplicationSelector : UserControl {
        public delegate void IsBusyDelegate(bool isBusy);
        /// <summary>
        /// Occurs when the control is busy refreshing the list of applications.
        /// </summary>
        public event IsBusyDelegate IsBusy;

        /// <summary>
        /// Occurs when the user selection changes.
        /// </summary>
        public event RoutedEventHandler SelectionChanged;

        private Window parentWindow;

        /// <summary>
        /// Gets the selected application.
        /// </summary>
        /// <value>The selected application.</value>
        public RBApplication SelectedApplication {
            get { return lstApplication.SelectedValue as RBApplication; }
        }
        /// <summary>
        /// Gets the selected bundles.
        /// </summary>
        /// <value>The selected bundles.</value>
        public ObservableSortedDictionary<string, string> SelectedBundles {
            get {
                ObservableSortedDictionary<string, string> items = new ObservableSortedDictionary<string, string>(new Comparers.DictionaryValueComparer(), new Comparers.StringEqualityComparer());
                foreach(KeyValuePair<string, string> itm in lstBundles.SelectedItems) {
                    items.Add(itm.Key, itm.Value);
                }
                return items;
            }
        }

        /// <summary>
        /// Gets the selected languages.
        /// </summary>
        /// <value>The selected languages.</value>
        public ObservableSortedDictionary<string, string> SelectedLanguages {
            get {
                ObservableSortedDictionary<string, string> items = new ObservableSortedDictionary<string, string>(new Comparers.DictionaryValueComparer(), new Comparers.StringEqualityComparer());
                foreach(KeyValuePair<string, string> itm in lstLanguages.SelectedItems) {
                    items.Add(itm.Key, itm.Value);
                }
                return items;
            }
        }

        /// <summary>
        /// Initializes a new <see cref="ApplicationSelector"/>.
        /// </summary>
        public ApplicationSelector() {
            InitializeComponent();
            this.Loaded += (s, re) => { 
                parentWindow = Window.GetWindow(this);
                RefreshApplications(this, null);
            };
        }

        /// <summary>
        /// Refreshes the list of applications using a background thread.
        /// </summary>
        public void RefreshApplications() {
            NavigationCommands.Refresh.Execute(null, null);
        }

        /// <summary>
        /// Refreshes the list of applications using a background thread.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void RefreshApplications(object sender, RoutedEventArgs e) {
            BackgroundWorker worker = new BackgroundWorker();
            worker.WorkerReportsProgress = true;
            worker.DoWork += (s, dwe) => {
                worker.ReportProgress(1, true);
                Database db = new Database();
                try {
                    dwe.Result = db.LoadApplications(true);
                } catch(Exception ex) {
                    dwe.Result = "Error connecting to the database: " + ex.Message;
                } finally {
                    if(db != null) {
                        try {
                            db.CloseConnection();
                        } catch { }
                    }
                }
            };
            worker.ProgressChanged += (s, pce) => {
                if(pce.UserState is bool && IsBusy != null) {
                    IsBusy((bool)pce.UserState);
                }
            };
            worker.RunWorkerCompleted += (s, rwe) => {
                if(IsBusy != null) {
                    IsBusy(false);
                }
                if(rwe.Result != null && rwe.Result is string) {
                    DialogBox.Show(parentWindow, rwe.Result.ToString(), "Database Error", DialogBox.DialogBoxType.OK, DialogBox.DialogBoxIcon.Error);
                } else {
                    DataContext = rwe.Result as List<RBApplication>;
                }
                if(lstApplication.HasItems) {
                    lstApplication.SelectedIndex = 0;
                }
            };
            worker.RunWorkerAsync();
        }

        /// <summary>
        /// Selects all languages and bundles for the newly selected application then fires the SelectionChanged event
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void lstApplication_SelectionChanged(object sender, RoutedEventArgs e) {
            lstBundles.SelectAll();
            lstLanguages.SelectAll();
            if(SelectionChanged != null) {
                SelectionChanged(this, e);
            }
        }

        /// <summary>
        /// Fires the SelectionChanged event
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void lstBundles_SelectionChanged(object sender, RoutedEventArgs e) {
            if(SelectionChanged != null) {
                SelectionChanged(this, e);
            }
        }

        /// <summary>
        /// Fires the SelectionChanged event
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void lstLanguages_SelectionChanged(object sender, RoutedEventArgs e) {
            if(SelectionChanged != null) {
                SelectionChanged(this, e);
            }
        }

        /// <summary>
        /// Validates the user's selection to check at least one application, bundle and language are selected. Providing feedback (MessageBoxes and changing the input focus) if necessary.
        /// </summary>
        /// <param name="provideFeedback"><c>true</c> if feedback (MessageBoxes and changing the input focus) should be provided.</param>
        /// <returns></returns>
        public bool ValidateSelection(bool provideFeedback) {
            bool valid = true;
            if(lstApplication.SelectedItems.Count == 0) {
                if(provideFeedback) {
                    DialogBox.Show(parentWindow, "No application was selected", "Error", DialogBox.DialogBoxType.OK, DialogBox.DialogBoxIcon.Error);
                }
                valid = false;
            } else if(lstBundles.SelectedItems.Count == 0) {
                if(provideFeedback) {
                    DialogBox.Show(parentWindow, "No bundles were selected", "Error", DialogBox.DialogBoxType.OK, DialogBox.DialogBoxIcon.Error);
                }
                valid = false;
            } else if(lstLanguages.SelectedItems.Count == 0) {
                if(provideFeedback) {
                    DialogBox.Show(parentWindow, "No languages were selected", "Error", DialogBox.DialogBoxType.OK, DialogBox.DialogBoxIcon.Error);
                }
                valid = false;
            }
            return valid;
        }
    }
}
